package cn.tedu.mall.front.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.front.mapper.FrontSkuMapper;
import cn.tedu.mall.front.service.IFrontSkuService;
import cn.tedu.mall.pojo.front.entity.FrontStockLog;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.product.vo.SkuStandardVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@DubboService
@Service
@Slf4j
public class FrontSkuServiceImpl extends FrontCacheServiceImpl<SkuStandardVO> implements IFrontSkuService {

    @Autowired
    private FrontSkuMapper frontSkuMapper;

    public static final String FRONT_SPU_SKU_PREFIX="front:spu:skus:";
    private static final String FRONT_SKUS_LOCK_SUFFIX=".lock";

    @Override
    public List<SkuStandardVO> getSkus(Long id) {
        String skusKey = FRONT_SPU_SKU_PREFIX+id;
        List<SkuStandardVO> listCache = getListCache(skusKey);
        if (listCache == null || listCache.size()==0){
            log.debug("根据spuId查询sku，缓存未命中!");
            String skusLockKey=skusKey+FRONT_SKUS_LOCK_SUFFIX;
            String randCode = new Random().nextInt(9000)+1000+"";
            try {
                boolean b = tryLock(skusLockKey, randCode);
                if (!b){
                    Thread.sleep(5000);
                    return getListCache(skusKey);
                }
                List<SkuStandardVO> skuStandardVOList = frontSkuMapper.selectSkusBySpuId(id);
                if (skuStandardVOList == null || skuStandardVOList.size()==0){
                    throw new CoolSharkServiceException
                            (ResponseCode.NOT_FOUND,"当前spu下没有sku");
                }
                setListCache(skusKey,skuStandardVOList,60*60*24l+new Random().nextInt(10000), TimeUnit.SECONDS);
                return skuStandardVOList;
            }catch (ClassCastException e){
                throw e;
            }catch (Exception e){
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"未知错误!");
            }finally {
               releaseLock(skusLockKey,randCode);
            }
        }
        log.debug("根据spuId查询sku，缓存命中!");
        return listCache;
    }

    @Override
    public SkuStandardVO getSku(Long skuId) {
        //引入缓存的前提 也要考虑雪崩 击穿 穿透
        return frontSkuMapper.selectSkuById(skuId);
    }

    @Override
    public List<SkuStandardVO> listSkuByIds(List<Long> ids) {
        List<SkuStandardVO> skuStandardVOS = new ArrayList<>();
        for (Long id : ids) {
            SkuStandardVO skuStandardVO = frontSkuMapper.selectSkuById(id);
            skuStandardVOS.add(skuStandardVO);
        }
        return skuStandardVOS;
    }

    @Override
    public void reduceSkusCounts(List<OrderItemAddDTO> items, String sn) {
        for (OrderItemAddDTO item : items) {
            Long skuId = item.getSkuId();
            Integer quantity = item.getQuantity();
            //update pms_sku set stock = stock-#{quantity}
            //where id=#{skuId} and stock > #{quantity}
            int success = frontSkuMapper.decrStock(skuId,quantity);
            if (success==0){
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                        "当前库存扣减失败,库存数量不够,skuId:"+skuId);
            }
            //成功减一个库存,记录一条库存日志
            FrontStockLog stockLog=new FrontStockLog();
            stockLog.setSkuId(skuId);
            stockLog.setOrderSn(sn);
            stockLog.setQuantity(quantity);
            stockLog.setGmtCreate(LocalDateTime.now());
            stockLog.setGmtModified(stockLog.getGmtCreate());
            frontSkuMapper.insertStockLog(stockLog);
        }
    }

    @Override
    public void returnStock(String sn) {
//用订单sn从日志中查询减库存日志,
        List<FrontStockLog> stockLogs=frontSkuMapper.selectStockLogBySn(sn);
        if (stockLogs==null||stockLogs.size()==0){
            //没有这个订单的日志记录,说明库存没减过.
            log.debug("sn:{},没有对应的库存减少日志,无任何操作");
        }else{
            for (FrontStockLog stockLog : stockLogs) {
                frontSkuMapper.incrStock(stockLog.getSkuId(),stockLog.getQuantity());
            }
        }
    }
}
